{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "23ff4bdd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            OLS Regression Results                            \n",
      "==============================================================================\n",
      "Dep. Variable:             Raw_return   R-squared:                       0.001\n",
      "Model:                            OLS   Adj. R-squared:                  0.000\n",
      "Method:                 Least Squares   F-statistic:                     1.546\n",
      "Date:                Thu, 23 Oct 2025   Prob (F-statistic):              0.214\n",
      "Time:                        13:44:12   Log-Likelihood:                 16953.\n",
      "No. Observations:                6058   AIC:                        -3.390e+04\n",
      "Df Residuals:                    6056   BIC:                        -3.389e+04\n",
      "Df Model:                           1                                         \n",
      "Covariance Type:                  HAC                                         \n",
      "===============================================================================\n",
      "                  coef    std err          z      P>|z|      [0.025      0.975]\n",
      "-------------------------------------------------------------------------------\n",
      "Intercept       0.0003      0.000      1.316      0.188      -0.000       0.001\n",
      "lRaw_return     0.0231      0.019      1.243      0.214      -0.013       0.059\n",
      "==============================================================================\n",
      "Omnibus:                      746.728   Durbin-Watson:                   1.999\n",
      "Prob(Omnibus):                  0.000   Jarque-Bera (JB):             7454.227\n",
      "Skew:                          -0.183   Prob(JB):                         0.00\n",
      "Kurtosis:                       8.422   Cond. No.                         67.8\n",
      "==============================================================================\n",
      "\n",
      "Notes:\n",
      "[1] Standard Errors are heteroscedasticity and autocorrelation robust (HAC) using 6 lags and without small sample correction\n",
      "方法4结果:\n",
      "            Log_return  Raw_Return\n",
      "year month                        \n",
      "1995 1       -0.141139   -0.131631\n",
      "     2       -0.023979   -0.023694\n",
      "     3        0.163651    0.177803\n",
      "     4       -0.109315   -0.103552\n",
      "     5        0.188901    0.207922\n",
      "\n",
      "方法5结果 (包含多个统计量):\n",
      "           Log_return                           Raw_return          \n",
      "                  sum      mean       std count       mean       std\n",
      "year month                                                          \n",
      "1995 1      -0.141139 -0.007428  0.016251    19  -0.007277  0.016140\n",
      "     2      -0.023979 -0.001411  0.033003    17  -0.000891  0.033609\n",
      "     3       0.163651  0.007115  0.023204    23   0.007401  0.023470\n",
      "     4      -0.109315 -0.005466  0.020374    20  -0.005255  0.020169\n",
      "     5       0.188901  0.008586  0.077844    22   0.011645  0.083211\n",
      "季度对数收益率汇总:\n",
      "\n",
      "季度末价格计算的收益率:\n",
      "年度对数收益率汇总:\n",
      "\n",
      "年末价格计算的收益率:\n",
      "\n",
      "使用groupby计算的年度收益率:\n",
      "滚动收益率 (基于对数收益率累加):\n",
      "            Rolling_5d_Return  Rolling_10d_Return  Rolling_20d_Return  \\\n",
      "Day                                                                     \n",
      "2025-08-25           0.041720            0.064705            0.079386   \n",
      "2025-08-26           0.037854            0.055229            0.071660   \n",
      "2025-08-27           0.009065            0.031732            0.051064   \n",
      "2025-08-28           0.019225            0.048318            0.075671   \n",
      "2025-08-29           0.008408            0.043594            0.083702   \n",
      "\n",
      "            Rolling_30d_Return  Rolling_60d_Return  \n",
      "Day                                                 \n",
      "2025-08-25            0.103394            0.160143  \n",
      "2025-08-26            0.103676            0.150627  \n",
      "2025-08-27            0.084644            0.125628  \n",
      "2025-08-28            0.092916            0.135781  \n",
      "2025-08-29            0.091511            0.139592  \n",
      "\n",
      "滚动收益率 (基于价格变化):\n",
      "            Rolling_5d_Price_Return  Rolling_10d_Price_Return  \\\n",
      "Day                                                             \n",
      "2025-08-25                 0.041720                  0.064705   \n",
      "2025-08-26                 0.037854                  0.055229   \n",
      "2025-08-27                 0.009065                  0.031732   \n",
      "2025-08-28                 0.019225                  0.048318   \n",
      "2025-08-29                 0.008408                  0.043594   \n",
      "\n",
      "            Rolling_20d_Price_Return  Rolling_30d_Price_Return  \\\n",
      "Day                                                              \n",
      "2025-08-25                  0.079386                  0.103394   \n",
      "2025-08-26                  0.071660                  0.103676   \n",
      "2025-08-27                  0.051064                  0.084644   \n",
      "2025-08-28                  0.075671                  0.092916   \n",
      "2025-08-29                  0.083702                  0.091511   \n",
      "\n",
      "            Rolling_60d_Price_Return  \n",
      "Day                                   \n",
      "2025-08-25                  0.160143  \n",
      "2025-08-26                  0.150627  \n",
      "2025-08-27                  0.125628  \n",
      "2025-08-28                  0.135781  \n",
      "2025-08-29                  0.139592  \n",
      "不同方法计算的累积收益率:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Cumulative_Log_Return</th>\n",
       "      <th>Cumulative_Return</th>\n",
       "      <th>Cumulative_Return_Prod</th>\n",
       "      <th>Cumulative_Return_Alt</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Day</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1995-01-03</th>\n",
       "      <td>-0.012409</td>\n",
       "      <td>-0.012333</td>\n",
       "      <td>-0.012333</td>\n",
       "      <td>-0.012333</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1995-01-04</th>\n",
       "      <td>0.009127</td>\n",
       "      <td>0.009169</td>\n",
       "      <td>0.009169</td>\n",
       "      <td>0.009169</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1995-01-05</th>\n",
       "      <td>-0.001514</td>\n",
       "      <td>-0.001513</td>\n",
       "      <td>-0.001513</td>\n",
       "      <td>-0.001513</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1995-01-06</th>\n",
       "      <td>-0.011035</td>\n",
       "      <td>-0.010974</td>\n",
       "      <td>-0.010974</td>\n",
       "      <td>-0.010974</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1995-01-09</th>\n",
       "      <td>-0.034340</td>\n",
       "      <td>-0.033757</td>\n",
       "      <td>-0.033757</td>\n",
       "      <td>-0.033757</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2025-08-25</th>\n",
       "      <td>1.790819</td>\n",
       "      <td>4.994361</td>\n",
       "      <td>4.994361</td>\n",
       "      <td>4.994361</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2025-08-26</th>\n",
       "      <td>1.786903</td>\n",
       "      <td>4.970931</td>\n",
       "      <td>4.970931</td>\n",
       "      <td>4.970931</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2025-08-27</th>\n",
       "      <td>1.769160</td>\n",
       "      <td>4.865922</td>\n",
       "      <td>4.865922</td>\n",
       "      <td>4.865922</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2025-08-28</th>\n",
       "      <td>1.780475</td>\n",
       "      <td>4.932675</td>\n",
       "      <td>4.932675</td>\n",
       "      <td>4.932675</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2025-08-29</th>\n",
       "      <td>1.784196</td>\n",
       "      <td>4.954793</td>\n",
       "      <td>4.954793</td>\n",
       "      <td>4.954793</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>7445 rows × 4 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            Cumulative_Log_Return  Cumulative_Return  Cumulative_Return_Prod  \\\n",
       "Day                                                                            \n",
       "1995-01-03              -0.012409          -0.012333               -0.012333   \n",
       "1995-01-04               0.009127           0.009169                0.009169   \n",
       "1995-01-05              -0.001514          -0.001513               -0.001513   \n",
       "1995-01-06              -0.011035          -0.010974               -0.010974   \n",
       "1995-01-09              -0.034340          -0.033757               -0.033757   \n",
       "...                           ...                ...                     ...   \n",
       "2025-08-25               1.790819           4.994361                4.994361   \n",
       "2025-08-26               1.786903           4.970931                4.970931   \n",
       "2025-08-27               1.769160           4.865922                4.865922   \n",
       "2025-08-28               1.780475           4.932675                4.932675   \n",
       "2025-08-29               1.784196           4.954793                4.954793   \n",
       "\n",
       "            Cumulative_Return_Alt  \n",
       "Day                                \n",
       "1995-01-03              -0.012333  \n",
       "1995-01-04               0.009169  \n",
       "1995-01-05              -0.001513  \n",
       "1995-01-06              -0.010974  \n",
       "1995-01-09              -0.033757  \n",
       "...                           ...  \n",
       "2025-08-25               4.994361  \n",
       "2025-08-26               4.970931  \n",
       "2025-08-27               4.865922  \n",
       "2025-08-28               4.932675  \n",
       "2025-08-29               4.954793  \n",
       "\n",
       "[7445 rows x 4 columns]"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np # 数据处理最重要的模块\n",
    "import pandas as pd # 数据处理最重要的模块\n",
    "import scipy.stats as stats # 统计模块\n",
    "import scipy\n",
    "# import pymysql  # 导入数据库模块\n",
    "\n",
    "from datetime import datetime # 时间模块\n",
    "import statsmodels.formula.api as smf  # OLS regression\n",
    "\n",
    "# import pyreadr # read RDS file\n",
    "\n",
    "from matplotlib import style\n",
    "import matplotlib.pyplot as plt  # 画图模块\n",
    "import matplotlib.dates as mdates\n",
    "\n",
    "\n",
    "from matplotlib.font_manager import FontProperties # 作图中文\n",
    "from pylab import mpl\n",
    "#mpl.rcParams['font.sans-serif'] = ['SimHei']\n",
    "#plt.rcParams['font.family'] = 'Times New Roman'\n",
    "\n",
    "\n",
    "#输出矢量图 渲染矢量图\n",
    "%matplotlib inline\n",
    "%config InlineBackend.figure_format = 'svg'\n",
    "\n",
    "from IPython.core.interactiveshell import InteractiveShell # jupyter运行输出的模块\n",
    "#显示每一个运行结果\n",
    "InteractiveShell.ast_node_interactivity = 'all'\n",
    "\n",
    "#设置行不限制数量\n",
    "#pd.set_option('display.max_rows',None)\n",
    "\n",
    "#设置列不限制数量\n",
    "pd.set_option('display.max_columns', None)\n",
    "data = pd.read_csv('000001.csv')\n",
    "data['Day'] = pd.to_datetime(data['Day'],format='%Y/%m/%d')\n",
    "data.set_index('Day', inplace = True)\n",
    "data.sort_values(by = ['Day'],axis=0, ascending=True)\n",
    "data\n",
    "data_new = data['1995-01':'2025-08'].copy()\n",
    "data_new['Close'] = pd.to_numeric(data_new['Close'])\n",
    "data_new['Preclose'] = pd.to_numeric(data_new['Preclose'])\n",
    "data_new\n",
    "# 计算000001上证指数日收益率 - 方法1：直接使用向量化操作（最推荐的方式）\n",
    "data_new['Raw_return'] = data_new['Close'] / data_new['Preclose'] - 1\n",
    "data_new['Log_return'] = np.log(data_new['Close']) - np.log(data_new['Preclose'])\n",
    "\n",
    "# 方法2：使用pandas的pct_change函数计算收益率（适用于时间序列数据）\n",
    "# 注意：这种方法需要数据已经按时间排序\n",
    "data_new['Pct_change_return'] = data_new['Close'].pct_change()\n",
    "\n",
    "# 方法3：使用apply方法（不推荐，因为速度较慢）\n",
    "data_new['Apply_return'] = data_new.apply(lambda row: row['Close'] / row['Preclose'] - 1, axis=1)\n",
    "\n",
    "# 方法4：使用diff和div方法组合（另一种向量化操作）\n",
    "data_new['Diff_div_return'] = data_new['Close'].diff() / data_new['Close'].shift(1)\n",
    "\n",
    "# 比较不同方法计算结果的差异\n",
    "data_new\n",
    "data_new['lRaw_return']= data_new['Raw_return'].shift(1)\n",
    "data_new['lLog_return']= data_new['Log_return'].shift(1)\n",
    "model_mom = smf.ols('Raw_return ~ lRaw_return', data=data_new['2000-01':'2024-12']).fit(\n",
    "    cov_type='HAC', cov_kwds={'maxlags': 6})\n",
    "print(model_mom.summary())\n",
    "# 方法5：使用for循环计算收益率（不推荐，效率低）\n",
    "# 这种方法在大数据集上会非常慢，仅作为教学示例\n",
    "\n",
    "# 创建新列存储结果\n",
    "if 'Loop_return' not in data_new.columns:\n",
    "    data_new['Loop_return'] = np.nan\n",
    "\n",
    "# 使用for循环计算\n",
    "for i in range(len(data_new)):\n",
    "    data_new.iloc[i, data_new.columns.get_loc('Loop_return')] = data_new.iloc[i, data_new.columns.get_loc('Close')] / data_new.iloc[i, data_new.columns.get_loc('Preclose')] - 1\n",
    "\n",
    "# 方法6：使用zip和enumerate组合（比纯for循环更Pythonic）\n",
    "close_values = data_new['Close'].values\n",
    "preclose_values = data_new['Preclose'].values\n",
    "loop_return_values = []\n",
    "\n",
    "for i, (close, preclose) in enumerate(zip(close_values, preclose_values)):\n",
    "    if preclose != 0 and not np.isnan(preclose):\n",
    "        loop_return_values.append(close / preclose - 1)\n",
    "    else:\n",
    "        loop_return_values.append(np.nan)\n",
    "\n",
    "data_new['Loop_return2'] = loop_return_values\n",
    "\n",
    "# 方法7：使用numpy的向量化操作（高效且简洁）\n",
    "data_new['Numpy_return'] = (data_new['Close'].values / data_new['Preclose'].values) - 1\n",
    "\n",
    "# 显示结果\n",
    "data_new\n",
    "# 方法1：使用resample函数计算月度对数收益率并转换为原始收益率\n",
    "# 这种方法适合对数收益率，因为对数收益率可以直接相加\n",
    "Month_data1 = data_new.resample('ME')['Log_return'].sum().to_frame(name='Log_return') \n",
    "Month_data1['Raw_Return'] = np.exp(Month_data1['Log_return']) - 1\n",
    "\n",
    "# 添加年月信息便于分析\n",
    "Month_data1['Year'] = Month_data1.index.year\n",
    "Month_data1['Month'] = Month_data1.index.month\n",
    "\n",
    "# 显示结果\n",
    "Month_data1.head()\n",
    "# 方法2：使用resample取月末价格计算月度收益率\n",
    "# 这种方法直接使用月末价格计算收益率，更符合金融实践\n",
    "Month_data2 = data_new.resample('ME')['Close'].last().to_frame()\n",
    "Month_data2['Preclose'] = Month_data2['Close'].shift(1)\n",
    "Month_data2['Raw_return'] = Month_data2['Close'] / Month_data2['Preclose'] - 1\n",
    "Month_data2['Log_return'] = np.log(Month_data2['Close']) - np.log(Month_data2['Preclose'])\n",
    "\n",
    "# 添加年月信息\n",
    "Month_data2['Year'] = Month_data2.index.year\n",
    "Month_data2['Month'] = Month_data2.index.month\n",
    "\n",
    "# 显示结果\n",
    "Month_data2.head()\n",
    "# “1990-12-12”日期格式 里面的year年份 month月份 day 直接提出取来\n",
    "data_new2 = data_new.copy()\n",
    "data_new2['year'] = data_new2.index.year\n",
    "data_new2['month'] = data_new2.index.month\n",
    "data_new2\n",
    "# 使用的时间、日期格式提取 字符串提出的方式 前四个字符当作年份 6-7字符是月份 提取出来的是字符串 变成数值\n",
    "# 方法3：使用groupby函数按年月分组计算月度收益率\n",
    "# 首先提取年月信息\n",
    "data_new3 = data_new.copy()\n",
    "data_new3['year'] = data_new3.index.year\n",
    "data_new3['month'] = data_new3.index.month\n",
    "\n",
    "# 使用groupby按年月分组，然后对每组的对数收益率求和\n",
    "Month_data3 = data_new3.groupby(['year', 'month'])['Log_return'].sum().to_frame()\n",
    "Month_data3['Raw_Return'] = np.exp(Month_data3['Log_return']) - 1\n",
    "\n",
    "# 显示结果\n",
    "Month_data3\n",
    "# 方法4：使用apply和lambda函数进行更灵活的分组计算\n",
    "# 这种方法可以对每个月的数据进行更复杂的操作\n",
    "Month_data4 = pd.DataFrame(\n",
    "    data_new3.groupby(['year', 'month'])['Log_return'].apply(lambda x: sum(x)))\n",
    "Month_data4.columns = ['Log_return']\n",
    "Month_data4['Raw_Return'] = np.exp(Month_data4['Log_return']) - 1\n",
    "\n",
    "# 方法5：使用agg函数同时计算多个统计量\n",
    "Month_data5 = data_new3.groupby(['year', 'month']).agg({\n",
    "    'Log_return': ['sum', 'mean', 'std', 'count'],\n",
    "    'Raw_return': ['mean', 'std']\n",
    "})\n",
    "\n",
    "# 显示结果\n",
    "print(\"方法4结果:\")\n",
    "print(Month_data4.head())\n",
    "print(\"\\n方法5结果 (包含多个统计量):\")\n",
    "print(Month_data5.head())\n",
    "# 计算季度收益率\n",
    "# 方法1：使用resample函数的'QE'参数（季度末）\n",
    "Quarter_data1 = data_new.resample('QE')['Log_return'].sum().to_frame(name='Log_return')\n",
    "Quarter_data1['Raw_Return'] = np.exp(Quarter_data1['Log_return']) - 1\n",
    "Quarter_data1['Year'] = Quarter_data1.index.year\n",
    "Quarter_data1['Quarter'] = Quarter_data1.index.quarter\n",
    "\n",
    "# 方法2：使用季度末价格计算\n",
    "Quarter_data2 = data_new.resample('QE')['Close'].last().to_frame()\n",
    "Quarter_data2['Preclose'] = Quarter_data2['Close'].shift(1)\n",
    "Quarter_data2['Raw_return'] = Quarter_data2['Close'] / Quarter_data2['Preclose'] - 1\n",
    "Quarter_data2['Log_return'] = np.log(Quarter_data2['Close']) - np.log(Quarter_data2['Preclose'])\n",
    "\n",
    "# 显示结果\n",
    "print(\"季度对数收益率汇总:\")\n",
    "Quarter_data1\n",
    "print(\"\\n季度末价格计算的收益率:\")\n",
    "Quarter_data2\n",
    "# 计算年度收益率\n",
    "# 方法1：使用resample函数的'YE'参数（年末）\n",
    "Year_data1 = data_new.resample('YE')['Log_return'].sum().to_frame(name='Log_return')\n",
    "Year_data1['Raw_Return'] = np.exp(Year_data1['Log_return']) - 1\n",
    "\n",
    "# 方法2：使用年末价格计算\n",
    "Year_data2 = data_new.resample('YE')['Close'].last().to_frame()\n",
    "Year_data2['Preclose'] = Year_data2['Close'].shift(1)\n",
    "Year_data2['Raw_return'] = Year_data2['Close'] / Year_data2['Preclose'] - 1\n",
    "Year_data2['Log_return'] = np.log(Year_data2['Close']) - np.log(Year_data2['Preclose'])\n",
    "\n",
    "# 方法3：使用groupby按年分组\n",
    "data_new4 = data_new.copy()\n",
    "data_new4['year'] = data_new4.index.year\n",
    "Year_data3 = data_new4.groupby('year')['Log_return'].sum().to_frame()\n",
    "Year_data3['Raw_Return'] = np.exp(Year_data3['Log_return']) - 1\n",
    "\n",
    "# 显示结果\n",
    "print(\"年度对数收益率汇总:\")\n",
    "Year_data1\n",
    "print(\"\\n年末价格计算的收益率:\")\n",
    "Year_data2\n",
    "print(\"\\n使用groupby计算的年度收益率:\")\n",
    "Year_data3\n",
    "# 计算滚动收益率（例如：过去30天、60天、90天的收益率 注意这里指的是前30个观测值）\n",
    "# 这在金融分析中非常常见，用于观察不同时间窗口的收益表现\n",
    "\n",
    "# 方法1：使用rolling窗口函数计算滚动对数收益率之和\n",
    "rolling_returns = pd.DataFrame()\n",
    "for window in [5, 10, 20, 30, 60]:\n",
    "    # 计算滚动窗口的对数收益率之和\n",
    "    rolling_log_return = data_new['Log_return'].rolling(window=window).sum()\n",
    "    # 转换为原始收益率\n",
    "    rolling_returns[f'Rolling_{window}d_Return'] = np.exp(rolling_log_return) - 1\n",
    "\n",
    "# 方法2：使用pct_change计算滚动价格变化\n",
    "rolling_price_returns = pd.DataFrame()\n",
    "for window in [5, 10, 20, 30, 60]:\n",
    "    rolling_price_returns[f'Rolling_{window}d_Price_Return'] = data_new['Close'].pct_change(periods=window)\n",
    "\n",
    "# 显示结果\n",
    "print(\"滚动收益率 (基于对数收益率累加):\")\n",
    "print(rolling_returns.tail())\n",
    "print(\"\\n滚动收益率 (基于价格变化):\")\n",
    "print(rolling_price_returns.tail())\n",
    "# 计算累积收益率\n",
    "# 累积收益率用于观察长期投资表现，从某个起始点开始累积\n",
    "\n",
    "# 方法1：使用对数收益率累加后转换\n",
    "# 这是最准确的方法，特别是对于长期累积\n",
    "cumulative_returns = pd.DataFrame()\n",
    "cumulative_returns['Cumulative_Log_Return'] = data_new['Log_return'].cumsum()\n",
    "cumulative_returns['Cumulative_Return'] = np.exp(cumulative_returns['Cumulative_Log_Return']) - 1\n",
    "\n",
    "# 方法2：使用cumprod函数直接累乘(1+r)\n",
    "# 这种方法在金融实践中也很常见\n",
    "cumulative_returns['Cumulative_Return_Prod'] = (1 + data_new['Raw_return']).cumprod() - 1\n",
    "\n",
    "# 方法3：使用pandas的累积函数\n",
    "cumulative_returns['Cumulative_Return_Alt'] = data_new['Raw_return'].add(1).cumprod().sub(1)\n",
    "\n",
    "# 显示结果\n",
    "print(\"不同方法计算的累积收益率:\")\n",
    "cumulative_returns"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
